/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo
*/

/*! \file Утилита тестирования средств лексического анализа библиотеки SIMODO core. Проект SIMODO.
*/

#include "simodo/module/ModuleCollector.h"
#include "simodo/inout/convert/functions.h"

#include <iostream>

using namespace simodo;

int main(int argc, char *argv[])
{
    std::string module_name   {"test"};
    std::string module_setter {"set_test_string"};
    std::string module_getter {"get_test_string"};

    if (argc > 1)
        module_name = argv[1];

    if (argc > 2)
        module_setter = argv[2];

    if (argc > 3)
        module_getter = argv[3];

    module::ModuleCollector collector({"bin/modules"});

    // Проверка работы сетера и гетера  
    std::shared_ptr<variable::Object> object1 = collector.produceObject(module_name);
    if (!object1) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    variable::Value ret11 = collector.invoke(*object1, module_getter, {});
    if (!collector.last_error().empty()) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    std::cout << module_name << " object1" << "." << module_getter << " returned: " 
              << inout::toU8(toString(ret11)) 
              << std::endl;

    collector.invoke(*object1, module_setter, {{u"",{u"collector call 1"}}});
    if (!collector.last_error().empty()) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    variable::Value ret13 = collector.invoke(*object1, module_getter, {});
    if (!collector.last_error().empty()) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    std::cout << module_name  << " object1" << "." << module_getter << " returned: " 
              << inout::toU8(toString(ret13)) 
              << std::endl;

    // Проверка, что нет зависимости между внешними модулями
    std::shared_ptr<variable::Object> object2 = collector.produceObject(module_name);
    if (!object1) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    variable::Value ret21 = collector.invoke(*object2, module_getter, {});
    if (!collector.last_error().empty()) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    std::cout << module_name  << " object2" << "." << module_getter << " returned: " 
              << inout::toU8(toString(ret21)) 
              << std::endl;

    collector.invoke(*object2, module_setter, {{u"",{u"collector call 2"}}});
    if (!collector.last_error().empty()) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    variable::Value ret23 = collector.invoke(*object2, module_getter, {});
    if (!collector.last_error().empty()) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    std::cout << module_name  << " object2" << "." << module_getter << " returned: " 
              << inout::toU8(toString(ret23)) 
              << std::endl;

    variable::Value ret14 = collector.invoke(*object1, module_getter, {});
    if (!collector.last_error().empty()) {
        std::cout << collector.last_error() << std::endl;
        return 1;
    }

    std::cout << module_name  << " object1" << "." << module_getter << " returned: " 
              << inout::toU8(toString(ret14)) 
              << std::endl;

    // Вывод:
    // test object1.get_test_string returned: "initial test string"
    // test object1.get_test_string returned: "collector call 1"
    // test object2.get_test_string returned: "initial test string"
    // test object2.get_test_string returned: "collector call 2"
    // test object1.get_test_string returned: "collector call 1"


    return 0;
}
